home *** CD-ROM | disk | FTP | other *** search
- /* $Id: identd.c,v 0.1 1994/05/22 21:41:23 qpliu Exp $
- * identd.c by qpliu 1994 -- this program is in the public domain.
- * RFC 1413 ident server using the linux /proc fs.
- * This probably could be done much more simply with perl.
- */
-
- /* Aug. 95 - modded by VectorX to accept a file of no more
- then 14 characters on one line, called .fakeid, in the
- users home directory, which will be substituted for the
- actual identity of the user being looked up. Re-define
- USERIDFILE and recompile to change he default lookup.
-
- To install just compile, rename /usr/sbin/in.identd to a
- backup, and replace w/this file.
- */
-
-
- #include <sys/types.h>
- #include <sys/fcntl.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <ctype.h>
- #include <netinet/in.h>
- #include <pwd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
-
- /* TIMEOUT is the number of seconds to wait before closing the connection if
- * the client doesn't provide the port pairs.
- */
- #define TIMEOUT 120
-
- /* PROCINFO_PATH is where the /proc tcp information is found */
- #define PROCINFO_PATH "/proc/net/tcp"
-
- /* USERIDFILE is the file that can spoof the identd information */
- #define USERIDFILE "/.fakeid"
-
- /* PROCINFO_BUFFER_SIZE must be bigger than 80 */
- #define PROCINFO_BUFFER_SIZE 2048
- #define SOCKET_BUFFER_SIZE 100
-
- unsigned short lport = 0, rport = 0;
-
- #define INVALID_PORT 0
- #define NO_USER 1
- #define HIDDEN_USER 2
- #define UNKNOWN_ERROR 3
-
- char *errors[] = {
- "INVALID-PORT", "NO-USER", "HIDDEN-USER", "UNKNOWN-ERROR"
- };
-
- void
- error (int c)
- {
- char str[80];
-
- sprintf (str, "%u , %u : ERROR : %s\r\n", lport, rport, errors[c]);
- write (1, str, strlen (str));
- exit (0);
- }
-
- void
- main ()
- {
- struct sockaddr_in sin;
- unsigned long here, there;
- int len = sizeof (sin);
- struct fd_set fdset;
- struct timeval timeout;
- char buffer[PROCINFO_BUFFER_SIZE > SOCKET_BUFFER_SIZE ?
- PROCINFO_BUFFER_SIZE : SOCKET_BUFFER_SIZE];
- char *spoofdir;
- char *spoofid;
- char spoofbuf[14];
-
- int index;
- enum {
- have_neither, have_lport_start, have_lport,
- have_comma, have_rport_start, have_both
- } read_state;
- int fd, spooffd, spooflen;
-
- if (getsockname (0, (struct sockaddr *) &sin, &len) < 0) exit (0);
- here = sin.sin_addr.s_addr;
- if (getpeername (0, (struct sockaddr *) &sin, &len) < 0) exit (0);
- there = sin.sin_addr.s_addr;
-
- /* prepare to read ports */
- FD_ZERO (&fdset);
- FD_SET (0, &fdset);
- timeout.tv_sec = TIMEOUT;
- timeout.tv_usec = 0;
-
- /* read ports from stdin */
- read_state = have_neither;
- index = 0;
- while (read_state != have_both && 1 == select (1, &fdset, NULL, NULL, &timeout)) {
- int i, newindex;
-
- len = read (0, buffer + index, SOCKET_BUFFER_SIZE - index);
- if (len <= 0)
- exit (0);
-
- i = index;
- newindex = 0;
-
- switch (read_state) {
- case have_neither:
- while (i < len + index) {
- if (isdigit (buffer[i])) {
- read_state = have_lport_start;
- break;
- }
- if (!isspace (buffer[i]))
- error (INVALID_PORT);
- i++;
- }
- newindex = i;
- /* fallthrough */
- case have_lport_start:
- while (i < len + index) {
- if (!isdigit (buffer[i])) {
- newindex = atoi (buffer + newindex);
- if (newindex != newindex&0xffff && newindex == 0)
- error (INVALID_PORT);
- lport = newindex;
- read_state = have_lport;
- newindex = i;
- break;
- }
- i++;
- }
- /* fallthrough */
- case have_lport:
- while (i < len + index) {
- if (',' == buffer[i]) {
- read_state = have_comma;
- ++i;
- break;
- }
- if (!isspace (buffer[i]))
- error (INVALID_PORT);
- i++;
- }
- newindex = i;
- /* fallthrough */
- case have_comma:
- while (i < len + index) {
- if (isdigit (buffer[i])) {
- read_state = have_rport_start;
- break;
- }
- if (!isspace (buffer[i]))
- error (INVALID_PORT);
- i++;
- }
- newindex = i;
- /* fallthrough */
- case have_rport_start:
- while (i < len + index) {
- if (!isdigit (buffer[i])) {
- newindex = atoi (buffer + newindex);
- if (newindex != newindex&0xffff && newindex == 0)
- error (INVALID_PORT);
- rport = newindex;
- read_state = have_both;
- newindex = i;
- break;
- }
- i++;
- }
- /* fallthrough */
- }
- index = i - newindex;
- memmove (buffer, buffer + newindex, index);
- FD_SET (0, &fdset);
- }
- if (read_state != have_both) exit (0);
-
- /* get info from /proc/net/tcp */
- fd = open (PROCINFO_PATH, O_RDONLY);
- if (fd < 0)
- error (UNKNOWN_ERROR);
- index = 0;
-
- /* linear search for matching addresses and ports */
- while (0 < (len = read (fd, buffer + index, PROCINFO_BUFFER_SIZE - index))) {
- int i, newindex;
- unsigned long l_here, l_there;
- unsigned short l_rport, l_lport;
- int uid;
-
- newindex = i = 0;
- while (i < len + index) {
- if (sscanf (buffer + i, "%*d: %lx:%hx %lx:%hx %*x %*x:%*x %*x:%*x %*x %d",
- &l_here, &l_lport, &l_there, &l_rport, &uid) == 5) {
- /* /proc/net/tcp displays addresses in net order and
- * ports in host order--how convenient.
- */
- if (here == l_here && lport == l_lport && there == l_there && rport == l_rport) {
- struct passwd *p = getpwuid (uid);
-
- if (NULL == p) error (UNKNOWN_ERROR);
-
- spoofdir = p->pw_dir;
- strcat(spoofdir, USERIDFILE);
- spooffd = open(spoofdir, O_RDONLY);
- if (spooffd < 0) {
- sprintf (buffer, "%u , %u : USERID : UNIX : %s\r\n",
- lport, rport, p->pw_name);
- }
- else
- {
- spooflen = read(spooffd, spoofbuf, sizeof(spoofbuf));
- spoofid = strtok(spoofbuf, "\r\n");
- sprintf (buffer, "%u , %u : USERID : UNIX : %s\r\n",
- lport, rport, spoofid);
- }
- write (1, buffer, strlen (buffer));
- exit (0);
- }
- }
- newindex = i;
- while (buffer[i++] != '\n' && i < len + index)
- ;
- }
- index = PROCINFO_BUFFER_SIZE - newindex;
- memmove (buffer, buffer + newindex, index);
- }
- error (NO_USER);
- }
-
- /* $Log: identd.c,v $
- * Revision 0.1 1994/05/22 21:41:23 qpliu
- * Seems to work.
- *
- */
-